package com.chenjiaru.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.chenjiaru.util.entity.IndexInfo;
import com.chenjiaru.util.entity.page.Page;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.get.*;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;

import java.io.IOException;
import java.util.*;

/**
 * es文档操作的工具类
 */
@Slf4j
public class ElasticSearchDocumentUtil {

    /**
     * 新增文档
     * @param obj   文档对象
     * @return
     */
    public static void insert(Object obj) {
        batchInsert(Collections.singletonList(obj));
    }

    /**
     * 获取文档
     * @param obj   文档对象
     * @return
     */
    public static void get(Object obj) {
        batchGet(Collections.singletonList(obj));
    }

    /**
     * 更新文档（更新不为null的字段）
     * @param obj   文档对象
     */
    public static void update(Object obj) {
        batchUpdate(Collections.singletonList(obj));
    }

    /**
     * 删除文档
     * @param obj   文档对象
     */
    public static void delete(Object obj) {
        batchDelete(Collections.singletonList(obj));
    }


    /**
     * 批量更新文档
     * @param list  文档对象集合
     * @param <E> 实体泛型
     */
    public static <E> void batchInsert(Collection<E> list){
        if(list == null || list.isEmpty()){
            return;
        }
        // 获取索引库信息（以第一个实体对象为准）
        IndexInfo indexInfo = getIndexInfo(list);
        // 批量新增
        BulkRequest bulkRequest = new BulkRequest();
        list.forEach(obj -> {
            JSONObject jsonObject = (JSONObject)JSON.toJSON(obj);
            bulkRequest.add(new IndexRequest(indexInfo.getIndexName()).id(jsonObject.getString(indexInfo.getPrimaryKey())).source(jsonObject.toJSONString(), XContentType.JSON));
        });
        try {
            BulkResponse bulkResponse = RestHighLevelClient.getInstance().bulk(bulkRequest, RequestOptions.DEFAULT);
            log.debug("bulkResponse={}", bulkResponse);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    /**
     * 批量更新文档（更新不为null的字段）
     * @param list  文档对象集合
     * @param <E>
     */
    public static <E> void batchUpdate(Collection<E> list){
        if(list == null || list.isEmpty()){
            return;
        }

        // 获取索引库信息（以第一个实体对象为准）
        IndexInfo indexInfo = getIndexInfo(list);

        // 批量新增
        BulkRequest bulkRequest = new BulkRequest();
        list.forEach(obj -> {
            JSONObject jsonObject = (JSONObject)JSON.toJSON(obj);
            // 设置请求体，对数据进行修改，记得去掉主键
            String id = jsonObject.getString(indexInfo.getPrimaryKey());
            jsonObject.remove(indexInfo.getPrimaryKey());
            bulkRequest.add(new UpdateRequest().index(indexInfo.getIndexName()).id(id).doc(jsonObject.toJSONString(), XContentType.JSON));
        });
        try {
            BulkResponse bulkResponse = RestHighLevelClient.getInstance().bulk(bulkRequest, RequestOptions.DEFAULT);
            log.debug("bulkResponse={}", bulkResponse);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 批量删除文档
     * @param list  文档对象集合
     * @param <E>
     */
    public static <E> void batchDelete(Collection<E> list){
        if(list == null || list.isEmpty()){
            return;
        }

        // 获取索引库信息（以第一个实体对象为准）
        IndexInfo indexInfo = getIndexInfo(list);

        // 批量删除
        BulkRequest bulkRequest = new BulkRequest();
        list.forEach(obj -> bulkRequest.add(new DeleteRequest().index(indexInfo.getIndexName()).id(((JSONObject)JSON.toJSON(obj)).getString(indexInfo.getPrimaryKey()))));
        try {
            BulkResponse bulkResponse = RestHighLevelClient.getInstance().bulk(bulkRequest, RequestOptions.DEFAULT);
            log.debug("bulkResponse={}", bulkResponse);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 批量获取文档（通过主键）
     * @param list  文档对象集合
     * @param <T>
     */
    public static <T> List<T> batchGet(Collection<T> list){
        List<T> result = new ArrayList<>();
        if(list == null || list.isEmpty()){
            return result;
        }

        // 获取索引库信息（以第一个实体对象为准）
        T first = list.stream().findFirst().get();
        IndexInfo indexInfo =  CommonUtil.getIndexInfo(first.getClass());

        // 批量获取
        MultiGetRequest bulkRequest = new MultiGetRequest();
        list.forEach(obj -> bulkRequest.add(indexInfo.getIndexName(), ((JSONObject)JSON.toJSON(obj)).getString(indexInfo.getPrimaryKey())));
        try {
            MultiGetResponse multiGetResponse = RestHighLevelClient.getInstance().mget(bulkRequest, RequestOptions.DEFAULT);
            MultiGetItemResponse[] multiGetResponseResponses = multiGetResponse.getResponses();
            if (multiGetResponseResponses != null && multiGetResponseResponses.length > 0) {
                Arrays.stream(multiGetResponseResponses).forEach(multiGetItemResponse -> {
                    GetResponse response = multiGetItemResponse.getResponse();
                    if (response != null) {
                        T entity = (T)CommonUtil.sourceToEntity(indexInfo.getPrimaryKey(), response.getId(), response.getSourceAsString(), first.getClass());
                        result.add(entity);
                    }
                });
            }
            log.debug("multiGetResponse={}", multiGetResponse);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 从批量对象中获取索引库信息（以第一个实体对象为准）
     * @param list  文档对象集合
     * @param <T>
     * @return
     */
    private static <T> IndexInfo getIndexInfo(Collection<T> list) {
        T first = list.stream().findFirst().get();
        return CommonUtil.getIndexInfo(first.getClass());
    }









    // ---高级搜索
    // 请求体
    public static <T> Page<T> search(SearchSourceBuilder builder, Class<T> clazz) {
        IndexInfo indexInfo = CommonUtil.getIndexInfo(clazz);
        // 创建搜索请求对象
        SearchRequest searchRequest = new SearchRequest(indexInfo.getIndexName());
        searchRequest.source(builder);
        try {
            SearchResponse searchResponse = RestHighLevelClient.getInstance().search(searchRequest, RequestOptions.DEFAULT);
            SearchHits hits = searchResponse.getHits();
            List<T> list = new ArrayList<>();
            hits.forEach(hit -> list.add(CommonUtil.sourceToEntity(indexInfo.getPrimaryKey(), hit.getId(), hit.getSourceAsString(), clazz)));
            Page<T> page = new Page<>(builder.from(), builder.size(), hits.getTotalHits().value, list);

            // 为了演示高亮
//            hits.forEach(hit -> {
//                log.info("高亮文本：{}", hit.getHighlightFields().get("about").fragments());
//            });

            return page;
        } catch(Exception e) {
            e.printStackTrace();
        }
        return new Page<>(builder.from(), builder.size(), 0, new ArrayList<>());
    }





}
